﻿namespace FSpec

open FSpec
open System.Text.RegularExpressions 

///<summary>String specific case ignorant assertions.</summary>
type IgnoreCaseFragment(positiveAssertion) =
    let normalize (str :string) : string =
        str.ToLower(System.Globalization.CultureInfo.CurrentCulture)
    
    let getContextualMessageFor fmt =
        if positiveAssertion then
                        format fmt [" "]
                    else
                        format fmt [" not "]

    member this.equal (expected:string) (actual:string) = 
        verify(fun()->
            if positiveAssertion =
               (normalize actual |> equals (normalize expected)) then
                null
            else
                let fmt = "The strings were{0}expected to be equal, ignoring case."
                createFailureFrom (getContextualMessageFor fmt)
                |> addLabelledValues ("Expected", expected) ("Actual", actual)
                |> toFailureException
        )

    member this.contain (expected:string) (actual:string) = 
        verify(fun()->
            if positiveAssertion = 
               (normalize actual |> containsTheString (normalize expected)) then 
                null
            else
                let fmt = "The actual string was{0}expected to contain the substring, ignoring case."
                createFailureFrom (getContextualMessageFor fmt)
                |> addLabelledValues ("Substring", expected) ("String",actual)
                |> toFailureException
        )

    member this.startWith (expected:string) (actual:string) = 
        verify(fun()->
            if positiveAssertion = 
               (normalize actual |> startsWith (normalize expected)) then 
                null
            else
                let fmt = "The actual string was{0}expected to start with the substring, ignoring case."
                createFailureFrom (getContextualMessageFor fmt)
                |> addLabelledValues ("Substring",expected) ("String", actual)
                |> toFailureException
        )

    member this.endWith expected actual = 
        verify(fun()->
            if positiveAssertion =
               (normalize actual |> endsWith (normalize expected)) then 
                null
            else
                let fmt = "The actual string was{0}expected to end with the substring, ignoring case."
                createFailureFrom (getContextualMessageFor fmt)
                |> addLabelledValues ("Substring", expected) ("String", actual)
                |> toFailureException
        )
    
    member this.matchExpression expression actual = 
        let regexOptions = RegexOptions.IgnoreCase 
        verify(fun()->
            if positiveAssertion =
               (actual |> matchExpression expression regexOptions) then 
                null
            else
                let fmt = "The string was{0}expected to match the regular expression, ignoring case."
                createFailureFrom (getContextualMessageFor fmt)
                |> addLabelledValues ("Regex", expression) ("Actual", actual)
                |> toFailureException
        )